package io.cici.cc.mybatis.lite.sql_source.scripting;

import io.cici.cc.mybatis.lite.builder.Builder;
import io.cici.cc.mybatis.lite.builder.BuilderException;
import io.cici.cc.mybatis.lite.mapping.SqlSource;
import io.cici.cc.mybatis.lite.session.Configuration;
import io.cici.cc.mybatis.lite.sql_source.DynamicSqlSource;
import io.cici.cc.mybatis.lite.sql_source.RawSqlSource;
import io.cici.cc.mybatis.lite.sql_source.scripting.tag.MixedTag;
import io.cici.cc.mybatis.lite.sql_source.scripting.tag.StaticTextTag;
import io.cici.cc.mybatis.lite.sql_source.scripting.tag.Tag;
import io.cici.cc.mybatis.lite.sql_source.scripting.tag.TextTag;
import io.cici.cc.mybatis.lite.sql_source.scripting.tagHandler.*;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class XMLScriptBuilder extends Builder {

    public final Map<String, TagHandler> tagToTagHandlerMap = new HashMap<>();
    private final io.cici.cc.mybatis.lite.parse.Node node;
    private final Class<?> parameterType;
    private boolean isDynamic;

    public XMLScriptBuilder(Configuration configuration, io.cici.cc.mybatis.lite.parse.Node node) {
        this(configuration, node, null);
    }

    public XMLScriptBuilder(Configuration configuration, io.cici.cc.mybatis.lite.parse.Node node, Class<?> parameterType) {
        super(configuration);
        this.node = node;
        this.parameterType = parameterType;
        initNodeHandlerMap();
    }

    private void initNodeHandlerMap() {

        tagToTagHandlerMap.put("foreach", new ForEachTagHandler(this));
        tagToTagHandlerMap.put("if", new IfTagHandler(this));
        tagToTagHandlerMap.put("choose", new ChooseTagHandler(this));
        tagToTagHandlerMap.put("when", new IfTagHandler(this));
        tagToTagHandlerMap.put("otherwise", new OtherwiseTagHandler(this));
        tagToTagHandlerMap.put("bind", new BindTagHandler());
    }

    public SqlSource parseScriptNode() {
        MixedTag mixedTag = parseDynamicTags(node);
        SqlSource sqlSource;
        if (isDynamic) {
            sqlSource = new DynamicSqlSource(configuration, mixedTag);
        } else {
            sqlSource = new RawSqlSource(configuration, mixedTag, parameterType);
        }
        return sqlSource;
    }

    public MixedTag parseDynamicTags(io.cici.cc.mybatis.lite.parse.Node node) {
        List<Tag> tagList = new ArrayList<>();
        NodeList childNodeList = node.getNode().getChildNodes();
        for (int i = 0; i < childNodeList.getLength(); i++) {
            io.cici.cc.mybatis.lite.parse.Node childNode = node.newNode(childNodeList.item(i));
            if (childNode.getNode().getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE || childNode.getNode().getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
                String body = childNode.getBody("");
                TextTag textTag = new TextTag(body);
                if (textTag.hasVariable()) {
                    tagList.add(textTag);
                    isDynamic = true;
                } else {
                    tagList.add(new StaticTextTag(body));
                }
            } else if (childNode.getNode().getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                String nodeName = childNode.getNode().getNodeName();
                TagHandler tagHandler = tagToTagHandlerMap.get(nodeName);
                if (tagHandler == null) {
                    throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
                }
                tagHandler.handle(childNode, tagList);
                isDynamic = true;
            }
        }
        return new MixedTag(tagList);
    }


}
